package com.gitee.wsl.struct.grammar.parser.context.ext

import com.gitee.wsl.struct.grammar.parser.Parser
import com.gitee.wsl.struct.grammar.parser.ParsingScope
import com.gitee.wsl.struct.grammar.parser.combinator.poll
import com.gitee.wsl.struct.grammar.parser.result.NotEnoughRepetition


suspend fun <R : Any> ParsingScope.repeatOneOrMore(p: Parser<R>): List<R> = repeat(p, atLeast = 1)

suspend fun <R : Any> ParsingScope.repeatZeroOrMore(p: Parser<R>): List<R> = repeat(p, atLeast = 0)

suspend fun <R : Any> ParsingScope.repeat(p: Parser<R>, atLeast: Int, atMost: Int = -1): List<R> {
    require(atLeast >= 0) { "atLeast must not be negative" }
    require(atMost == -1 || atLeast <= atMost) { "atMost has invalid value" }

    val startOffset = position
    val results = mutableListOf<R>()
    var repetition = 0
    while (atMost == -1 || repetition < atMost) {
        results += poll(p) ?: break
        repetition++
    }

    if (repetition < atLeast) fail(NotEnoughRepetition(startOffset, atLeast, repetition))
    return results
}